/**
 * ReportGear(2011)
 */
package com.reportgear.designer.gui.component.list;

import java.awt.Component;
import java.awt.Rectangle;
import java.util.Vector;

import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;

import com.reportgear.core.api.Nameable;
import net.abbp.core.util.StringUtils;

/**
 * Nameable对象编辑列表
 * 
 * @version 1.0 2011-4-25
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
public class JNameEditList extends JList implements CellEditorListener {
	private static final long serialVersionUID = 7394932703479426958L;
	private boolean hasIcon = false;
	private boolean editable = true;
	protected transient ListCellEditor cellEditor;
	protected transient Component editorComp;
	protected transient int editingIndex;

	private String oldName;

	public JNameEditList(ListModel dataModel) {
		super(dataModel);
	}

	public JNameEditList(Object[] listData) {
		super(listData);
	}

	public JNameEditList(Vector<?> listData) {
		super(listData);
	}

	public JNameEditList() {
	}

	public void setHasIcon(boolean hasIcon) {
		this.hasIcon = hasIcon;
	}

	public boolean hasIcon() {
		return this.hasIcon;
	}

	public void setEditable(boolean editable) {
		this.editable = editable;
	}

	public boolean isEditable() {
		return this.editable;
	}

	public void addModifyNameActionListener(ModifyNameActionListener lstnr) {
		this.listenerList.add(ModifyNameActionListener.class, lstnr);
	}

	public void removeModifyNameActionListener(ModifyNameActionListener lstnr) {
		this.listenerList.remove(ModifyNameActionListener.class, lstnr);
	}

	public void fireModifyNameEvent(int index, String oldName, String newName) {
		for (ModifyNameActionListener lstnr : this.getListeners(ModifyNameActionListener.class)) {
			lstnr.nameModified(index, oldName, newName);
		}
	}

	@SuppressWarnings("serial")
	public ListCellEditor getCellEditor() {
		if (this.cellEditor == null) {
			this.cellEditor = new DefaultListCellEditor(new JTextField()) {
				public boolean stopCellEditing() {
					boolean bool = super.stopCellEditing();
					stopEditing();

					return bool;
				}
			};

			this.cellEditor.addCellEditorListener(this);
		}

		return this.cellEditor;
	}

	public void setCellEditor(ListCellEditor editor) {
		this.cellEditor = editor;
	}

	public String getNameAt(int index) {
		Nameable nameObj = (Nameable) getModel().getElementAt(index);

		if (nameObj != null) {
			return nameObj.getName();
		}

		return "";
	}

	public void setNameAt(String name, int index) {
		Nameable nameObj = (Nameable) getModel().getElementAt(index);

		if (nameObj == null) {
			return;
		}

		String oldName = nameObj.getName();
		nameObj.setName(name);

		this.fireModifyNameEvent(index, oldName, name);
	}

	public boolean editItemAt(int index) {
		if (!this.editable) {
			return false;
		}

		if ((this.cellEditor != null) && (!this.cellEditor.stopCellEditing())) {
			return false;
		}

		if ((index < 0) || (index >= getModel().getSize())) {
			return false;
		}

		ListCellEditor editor = getCellEditor();
		Object value = editor.getCellEditorValue();

		if (!StringUtils.isEmpty(value)) {
			this.oldName = value.toString();
		}

		if (editor != null) {
			this.editorComp = prepareEditor(editor, index);
			if (this.editorComp == null)
				return false;

			Rectangle rect = getCellBounds(index, index);

			if (this.hasIcon)
				rect.setRect(rect.x + 20, rect.y, rect.width - 20, rect.height);

			this.editorComp.setBounds(rect);
			add(this.editorComp);
			this.editorComp.validate();
			this.editorComp.requestFocus();

			if (this.editorComp instanceof JTextField)
				((JTextField) this.editorComp).selectAll();

			setEditingIndex(index);

			return true;
		}

		return false;
	}

	private Component prepareEditor(ListCellEditor editor, int index) {
		String name = getNameAt(index);
		boolean bool = isSelectedIndex(index);

		Component c = editor.getListCellEditorComponent(this, name, bool, index);

		return c;
	}

	private void setEditingIndex(int index) {
		this.editingIndex = index;
	}

	public void editingCanceled(ChangeEvent evt) {
		removeComp();
	}

	public void editingStopped(ChangeEvent evt) {
		stopEditing();
	}

	public void stopEditing() {
		ListCellEditor editor = getCellEditor();
		if ((editor == null) || (this.editorComp == null)) {
			return;
		}

		Object value = editor.getCellEditorValue();
		String name = StringUtils.isEmpty(value) ? this.oldName : String.valueOf(value);

		setNameAt(name, this.editingIndex);

		removeComp();
	}

	private void removeComp() {
		if (this.editorComp != null) {
			remove(this.editorComp);
		}
		Rectangle rect = getCellBounds(this.editingIndex, this.editingIndex);
		repaint(rect);

		setEditingIndex(-1);
		this.editorComp = null;
	}
}